package knowledge.StringIntern;

/**
 * @Author: kkyeer
 * @Description: 字符串初始化，字符串连接，intern()方法对引用地址的影响
 * @Date:Created in 22:57 2019/4/7
 * @Modified By:
 */
public class TestCase {
    public static void main(String[] args) {
        String s1 = new String("1") + new String("1") + new String("1");
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            上面这段代码，在运行时会在堆上创建对象"1"并在字符串常量池中创建对应的引用，
            同时由于字符串常量池中没有值为"111"的对象，因此会在堆上创建一个值为"111"的对象，
            s1指向刚创建的这个"111"对象，但不会在常量池中新创建值为"111"的引用，因此常量池中仍旧
            没有值为"111"的对象

                                       ↓↓↓↓↓↓↓↓内存状态↓↓↓↓↓↓↓↓↓
            --------------------------------------堆--------------------------------------------
            addr1("1")
            addr2("111")
            ------------------------------------------------------------------------------------

            ---------------------------------字符串常量池---------------------------------------
            addr1("1")
            ------------------------------------------------------------------------------------

            ---------------------------------------变量-----------------------------------------
            s1 -> addr2
            ------------------------------------------------------------------------------------
         */
        String s2 = new String("11") + new String("1");
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            上面这段代码，在运行时会在堆上创建对象"11"并在字符串常量池中创建对应的引用，
            同时由于字符串常量池中仍旧没有值为"111"的对象，因此会在堆上创建一个值为"111"的对象，
            s2指向刚创建的这个"111"对象，
            注意，此"111"对象地址与s1不同，此时在堆上存在两个值都为"111"的String对象

                                       ↓↓↓↓↓↓↓↓内存状态↓↓↓↓↓↓↓↓↓
            --------------------------------------堆--------------------------------------------
            addr1("1")
            addr2("111")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------字符串常量池---------------------------------------
            addr1("1")
            addr3("11")
            ------------------------------------------------------------------------------------

            ---------------------------------------变量-----------------------------------------
            s1 -> addr2
            s2 -> addr4
            ------------------------------------------------------------------------------------
         */
        System.out.println(s1 == s2);
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            根据上面的运行过程可知，s1和s2分别指向堆上两个对象，只是堆上的对象恰巧值均为"111",
            因此打印false
         */
        s2.intern();
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            根据JDK7以后的实现，上面这句代码会检查字符串常量区，此时字符串常量区中没有值为"111"
            的引用，因此，会将s2的引用复制到字符串常量区

                                       ↓↓↓↓↓↓↓↓内存状态↓↓↓↓↓↓↓↓↓
            --------------------------------------堆--------------------------------------------
            addr1("1")
            addr2("111")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------字符串常量池---------------------------------------
            addr1("1")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------------变量-----------------------------------------
            s1 -> addr2
            s2 -> addr4
            ------------------------------------------------------------------------------------
         */
        String s3 = "111";
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            执行了上述intern()过程后，字符串常量区中已有值为"111"的引用，根据实现，s3赋值为常量
            区中值为"111"对应的引用也就是s2指向的堆上那个对象的地址

                                       ↓↓↓↓↓↓↓↓内存状态↓↓↓↓↓↓↓↓↓
            --------------------------------------堆--------------------------------------------
            addr1("1")
            addr2("111")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------字符串常量池---------------------------------------
            addr1("1")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------------变量-----------------------------------------
            s1 -> addr2
            s2 -> addr4
            s3 -> addr4
            ------------------------------------------------------------------------------------
         */
        System.out.println(s2 == s3);
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            s3和s2指向相同的堆上的对象，因此结果为true
         */
        String s4 = s1.intern();
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            因为字符串常量区中已有值为"111"的引用，因此此方法不会对字符串常量区中的值产生影响，
            但因为inter()方法返回的是字符串常量区中的引用，因此s4指向s2对应的对象

                                       ↓↓↓↓↓↓↓↓内存状态↓↓↓↓↓↓↓↓↓
            --------------------------------------堆--------------------------------------------
            addr1("1")
            addr2("111")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------字符串常量池---------------------------------------
            addr1("1")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------------变量-----------------------------------------
            s1 -> addr2
            s2 -> addr4
            s3 -> addr4
            s4 -> addr4
            ------------------------------------------------------------------------------------
         */
        System.out.println(s4 == s1);
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            s4和s1指向堆上的不同的对象，因此结果为false
         */

        String s6 = new String("1");
        String s7 = "1";
        String s8 = s6.intern();
        /*
                                        ↓↓↓↓↓↓↓↓解析↓↓↓↓↓↓↓↓↓
            根据上面的内存状态可知，s6仍旧指向堆上一个新建的值为"1"的对象，
            s6.inter()返回的是字符串常量区已有的值为"1"的对象地址，
            s8也等于这个地址

                                       ↓↓↓↓↓↓↓↓内存状态↓↓↓↓↓↓↓↓↓
            --------------------------------------堆--------------------------------------------
            addr1("1")
            addr2("111")
            addr3("11")
            addr4("111")
            addr5("1")
            ------------------------------------------------------------------------------------

            ---------------------------------字符串常量池---------------------------------------
            addr1("1")
            addr3("11")
            addr4("111")
            ------------------------------------------------------------------------------------

            ---------------------------------------变量-----------------------------------------
            s1 -> addr2
            s2 -> addr4
            s3 -> addr4
            s4 -> addr4
            s6 -> addr5
            s7 -> addr1
            s8 -> addr1
            ------------------------------------------------------------------------------------


         */
        System.out.println(s7 == s6);
        System.out.println(s8 == s6);
        System.out.println(s7 == s8);

        /*
            根据上面的内存状态可知，打印结果为：
            false
            false
            true
         */
    }
}
